package com.nightpiter.view.drawer.dynamic;

import java.util.ArrayList;
import java.util.HashMap;

import com.nightpiter.model.objects.Hub;
import com.nightpiter.model.objects.Station;
import com.nightpiter.view.Calculator;
import com.nightpiter.view.Calculator.Mode;
import com.nightpiter.view.graphics.Canvas;
import com.nightpiter.view.graphics.PointF;

/**
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 * 
 */
class AmoebaUltimate {

	/** the Amoeba to call the draw method */
	private Amoeba rootAmoeba;

	/** array of primitive Amoebas that make up this Amoeba */
	private HashMap<Station, PrimitiveAmoeba> primitiveAmoebasMap;

	private Structure structure;

	private static int counter;

	/**
	 * Complex Amoeba constructor
	 * 
	 * @param hub
	 * @param mode
	 * @param structure
	 */
	public AmoebaUltimate(Hub hub, Mode mode, Structure structure) {
		this.structure = structure;
		primitiveAmoebasMap = new HashMap<Station, PrimitiveAmoeba>(hub
				.getStations().size(), 1);
		Amoeba[] amoebas = new Amoeba[hub.getStations().size()];
		int i = 0;
		for (Station station : hub.getStations()) {
			int color;
			if (station.getLines().size() == 1) {
				color = station.getLines().get(0).getColor();
			} else {
				color = Config.DEFAULT_COLOR;
			}
			PrimitiveAmoeba primitiveAmoeba = new PrimitiveAmoeba(this,
					station, color, new PointF(station, mode));
			primitiveAmoebasMap.put(station, primitiveAmoeba);
			amoebas[i] = primitiveAmoeba;
			i++;
		}

		int level = amoebas.length;
		float minDistance;
		float distance;
		int nearestJ = 0, nearestK = 1;
		while (level > 1) {
			minDistance = Float.POSITIVE_INFINITY;
			for (int j = 0; j < level; j++) {
				Amoeba evenAmoeba = amoebas[j];
				for (int k = j + 1; k < level; k++) {
					Amoeba oddAmoeba = amoebas[k];
					distance = computeDistance(evenAmoeba, oddAmoeba);
					if (distance < minDistance) {
						minDistance = distance;
						nearestJ = j;
						nearestK = k;
					}

				}
			}
			IntermediateAmoeba intermediateAmoeba = new IntermediateAmoeba(
					amoebas[nearestJ], amoebas[nearestK]);
			if (nearestJ != level - 1) {
				amoebas[nearestJ] = intermediateAmoeba;
				amoebas[nearestK] = amoebas[level - 1];
			} else {
				amoebas[nearestK] = intermediateAmoeba;
			}

			level--;
			amoebas[level] = null;
		}

		rootAmoeba = amoebas[0];

	}

	/**
	 * Simple Amoeba constructor
	 * 
	 * @param station
	 * @param mode
	 * @param structure
	 */
	public AmoebaUltimate(Station station, Mode mode, Structure structure) {
		this.structure = structure;
		primitiveAmoebasMap = new HashMap<Station, PrimitiveAmoeba>(1, 1);
		int color;
		if (station.getLines().size() == 1) {
			color = station.getLines().get(0).getColor();
		} else {
			color = Config.DEFAULT_COLOR;
		}
		PrimitiveAmoeba primitiveAmoeba = new PrimitiveAmoeba(this, station,
				color, new PointF(station, mode));
		primitiveAmoebasMap.put(station, primitiveAmoeba);
		rootAmoeba = primitiveAmoeba;
	}

	private static PointF tempCoordF;

	private static float computeDistance(Amoeba evenAmoeba, Amoeba oddAmoeba) {
		tempCoordF = PointF.averaged(evenAmoeba.coordF, oddAmoeba.coordF,
				evenAmoeba.size, oddAmoeba.size);

		float maxDistance = Float.NEGATIVE_INFINITY;
		float distance;
		for (PointF eachCoordF : evenAmoeba.coords) {
			distance = tempCoordF.distanceTo(eachCoordF);
			if (distance > maxDistance) {
				maxDistance = distance;
			}
		}
		for (PointF eachCoordF : oddAmoeba.coords) {
			distance = tempCoordF.distanceTo(eachCoordF);
			if (distance > maxDistance) {
				maxDistance = distance;
			}
		}

		return maxDistance;
	}

	/** neighbor-to-link mapping */
	private HashMap<AmoebaUltimate, BacillusUltimate> bacillusUltimateMap = new HashMap<AmoebaUltimate, BacillusUltimate>();

	public BacillusUltimate searchBacillusUltimate(
			AmoebaUltimate neighborAmoebaUltimate) {
		BacillusUltimate bacillusUltimate = bacillusUltimateMap
				.get(neighborAmoebaUltimate);
		if (bacillusUltimate == null) {
			bacillusUltimate = new BacillusUltimate(this,
					neighborAmoebaUltimate);
			structure.addBacillusUltimate(bacillusUltimate);
		}
		return bacillusUltimate;
	}

	void addNeighbor(AmoebaUltimate neighborAmoebaUltimate,
			BacillusUltimate bacillusUltimate) {
		this.bacillusUltimateMap.put(neighborAmoebaUltimate, bacillusUltimate);
	}

	public void applyCalculator(Calculator calculator) {
		rootAmoeba.applyCalculator(calculator);
	}

	public void addDrawnAmoebas(ArrayList<Amoeba> drawnAmoebas) {
		rootAmoeba.addDrawnAmoebas(drawnAmoebas);
	}

	public void draw(Canvas canvas) {
		rootAmoeba.draw(canvas);
	}

	public HashMap<Station, PrimitiveAmoeba> getPrimitiveAmoebasMap() {
		return primitiveAmoebasMap;
	}

	public int getNextOrder() {
		return ++counter;
	}

}
